package com.sfpay.coreplatform.member.service.inner.impl;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sfpay.coreplatform.member.common.MemberResponseCode;
import com.sfpay.coreplatform.member.common.constant.Constants;
import com.sfpay.coreplatform.member.common.enums.ChannelCode;
import com.sfpay.coreplatform.member.common.enums.MemberLockStatus;
import com.sfpay.coreplatform.member.common.enums.MemberType;
import com.sfpay.coreplatform.member.common.util.DateUtil;
import com.sfpay.coreplatform.member.common.util.EncryptUtil;
import com.sfpay.coreplatform.member.kernel.boot.CacheParam;
import com.sfpay.coreplatform.member.persistence.dao.IEnterpriseManageDao;
import com.sfpay.coreplatform.member.persistence.dao.IMemberLockManageDao;
import com.sfpay.coreplatform.member.persistence.dao.IMemberManageDao;
import com.sfpay.coreplatform.member.persistence.dao.IOperatorManagerDao;
import com.sfpay.coreplatform.member.service.exception.MemberServiceException;
import com.sfpay.coreplatform.member.service.inner.IMemberHelpService;
import com.sfpay.coreplatform.member.service.validate.CommonCheckUtil;
import com.sfpay.coreplatform.member.valueobject.dto.EnterpriseMember;
import com.sfpay.coreplatform.member.valueobject.dto.Member;
import com.sfpay.coreplatform.member.valueobject.tmo.MemberLockInfo;
import com.sfpay.coreplatform.member.valueobject.tmo.OperatorInfo;
import com.sfpay.pubcenter.domain.BaseParam;

@Service
public class MemberHelpServiceImpl implements IMemberHelpService 
{
	@Resource
	private CacheParam cacheParam;
	
	@Resource 
	private IMemberManageDao memberManageDao;
	
	@Resource
	private IOperatorManagerDao operatorManagerDao;
	
	@Resource
	private IMemberLockManageDao memberLockManageDao;
	
	@Resource
	private IEnterpriseManageDao enterpriseManageDao;

	@Override
	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	public long generateMemberNo(MemberType memberType, String channelCode)
	{
		String memberTypeV = MemberType.convertToValue(memberType);
		String sysSourceV = ChannelCode.convertToValue(channelCode);
		String seq = memberManageDao.getMemberNoSeq(); //9位序列{（1,000,000,000 – sequence mod 1,000,000,000）}
		Random random = new Random();
		int ran = random.nextInt(10); //产生一位随机数
		int gd = 1; //从系统参数表中取固定值 一位
		//1位固定位+1位随机数+（1,000,000,000 – sequence mod 1,000,000,000）
		String gener = "" + gd + ran + seq; //11位
		//下面位置结对交换（位置从右往左，最右边为第1位）：（11，4）、（10，2）、（8，3）
		StringBuffer sbuff = new StringBuffer();
		sbuff.append(gener.substring(7,8));
		sbuff.append(gener.substring(9,10));
		sbuff.append(gener.substring(2,3));
		sbuff.append(gener.substring(8,9));
		sbuff.append(gener.substring(4,7));
		sbuff.append(gener.substring(0,1));
		sbuff.append(gener.substring(3,4));
		sbuff.append(gener.substring(1,2));
		sbuff.append(gener.substring(10,11));
		//个人/企业标识（1位数字）+ 渠道编码（2位数字）+ 序号（11位数字）
		String mr = memberTypeV + sysSourceV + sbuff;
		long memberNo = Long.parseLong(mr);
		return memberNo;
	}

	@Override
	@Transactional(rollbackFor= MemberServiceException.class,propagation=Propagation.REQUIRES_NEW)
	public Map<String, Integer> authMemberLogin(String pwd, String mobile,String mail,String loginName,MemberType memberType) throws MemberServiceException
	{
		int tryTimes = 0;//是否是第三次失败
		//获取配置中心配置：最大失败尝试次数
		BaseParam maxLoginFail_Times = cacheParam.getValue(Constants.MAX_LOGINFAIL_TIMES);
		//获取配置中心配置：登录的时候，多少的一个周期内，用户登录统计（以分为单位）
		BaseParam loginFail_CycleTime = cacheParam.getValue(Constants.LOGIN_FAIL_CYCLE_TIME);
		//获取配置中心配置，会员在输入N次密码后，被锁定后。系统自动解锁时间（以分钟为单位）
		BaseParam loginFail_unlockTime = cacheParam.getValue(Constants.LOGIN_FAIL_UNLOCK_TIME);
			
		/**
		 * 
		 * 
		 * 对于NORMAL流程：
		 *      	密码匹配
		 *      		存在登录失败
		 *      			A1 更新操作员最后成功登录时间，清除会员表数据	
		 *      		不存在登录失败
		 *      			A2 更新操作员最后成功登录时间
		 *      	密码不匹配
		 *      		存在登录失败
		 *      			超过一个周期		
		 *      				B 更新会员锁定记录，失败次数为1，第一次和最后失败登录时间相同，为当前时间
		 *      			没有超过一个周期
		 *      				是否超过一个配置	
	     *   					C 超过最大配置，更新会员锁定表记录和操作员表会员锁定状态AUTOLOCK
	     *     					D 没有超过最大配置，更新会员锁定表记录，失败次数+1，最后失败登录时间为当前时间
		 *     			不存在登录失败
		 *       				F 新增会员锁定记录，失败次数为1，第一次和最后失败登录时间相同，为当前时间
		 * 对于MANUALLOCK流程
		 *      直接返回提示信息，用户已经被管理员禁止行为....
		 * 对于AUTOLOCK流程
		 * （除去脏数据）
		 *      超过设置解锁时间
		 *      	密码匹配	
		 *      		A：更新操作员表上次成功登录的时间，会员锁定状态NORAML，同时删除会员锁定表数据
		 *          密码不匹配
		 *          	B：更新操作员表会员锁定状态为NORAML，更新锁定表第一次登录失败时间，最后一次失败时间，失败次数为1
		 *      没有超过解锁时间
		 * 			直接返回信息，提示用户已经输入N次密码，请M分钟后重试
		 * 
		 */
		//校验OMS配置信息，是否完整
		checkSystemParam(maxLoginFail_Times,loginFail_CycleTime,loginFail_unlockTime);

		int maxLoginFailTimes = Integer.parseInt(maxLoginFail_Times.getParamValue());//最大失败尝试次数
		int loginFailCycleTime = Integer.parseInt(loginFail_CycleTime.getParamValue());//一个周期时间（分）
		int loginFailUnlockTime = Integer.parseInt(loginFail_unlockTime.getParamValue());//自动解锁时间(分)
		
		MemberLockInfo memberLockInfo = memberLockManageDao.queryMemberLockInfo(mobile, mail,loginName, memberType);
		//根据会员信息，查询操作员信息
		OperatorInfo operatorInfo;
		int counts = 0;
		operatorInfo = operatorManagerDao.queryOperator(mobile, mail, loginName, null, "",memberType);
		
		if(MemberLockStatus.NORMAL == operatorInfo.getLockStatus())
		{
			//NORAML流程处理
			if(EncryptUtil.encryptPwd(pwd).equals(operatorInfo.getPwd()))
			{
				//密码匹配,更新操作员最后成功登录时间
				counts = operatorManagerDao.updateOperatorWhenLogin(operatorInfo , MemberLockStatus.NORMAL , true);//第三个参数为true：需要更新最后成功登入时间
				if(counts != 1)
				{
					throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
				}
				//判断是为是之前是否登录失败过
				if(memberLockInfo != null)
				{
					//之前存在登录失败，删除旧数据
					counts = memberLockManageDao.deleteMemberLockInfo(memberLockInfo.getMemberNo(),memberLockInfo.getOperatorID());
					if(counts != 1)
					{
						throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
					}
				}
			}
			else 
			{
				//密码不匹配
				if(memberLockInfo != null)
				{
					//之前存在登录失败，判断是否在一个统计周期范围内
					boolean  isOneCycle = DateUtil.isOneCycle(memberLockInfo.getCycleBeginDate(), 
							memberLockInfo.getCurrentDate(), loginFailCycleTime);//是否一个周期内
					if(isOneCycle)
					{
						int currentFailTryTimes  = memberLockInfo.getCycleFailTimes();//当前失败重试次数
						if(currentFailTryTimes + 1 ==  maxLoginFailTimes)
						{
							//超过最大的配置：失败重试次数。更新会员锁定表记录和操作员表会员锁定状态AUTOLOCK
							counts = operatorManagerDao.updateOperatorWhenLogin(operatorInfo , MemberLockStatus.AUTOLOCK , false);//第三个参数为false：不需要更新最后成功登入时间
							if(counts != 1)
							{
								throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
							}
							tryTimes = Constants.TRY_TIMES_3;
						}
						else
						{
							//区分第一次和第二次失败
							tryTimes = Constants.TRY_TIMES_2;
						}
						
						//更新会员锁定表记录，失败次数+1，最后失败登录时间更新
						counts = memberLockManageDao.updateMemberLockInfo(memberLockInfo.getMemberNo(),memberLockInfo.getOperatorID(),currentFailTryTimes+1, false);
						if(counts != 1)
						{
							throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
						}
					}
					else
					{
						//超过一个周期,失败次数为1，第一次和最后失败登录时间相同，为当前时间
						counts = memberLockManageDao.updateMemberLockInfo(memberLockInfo.getMemberNo(),memberLockInfo.getOperatorID(),1 , true);//标示重置开始和结束时间
						if(counts != 1)
						{
							throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
						}
					}
				}
				else
				{
					//之前不存在登录失败记录，为第一次登录失败。新增会员锁定记录，失败次数为1，第一次和最后失败登录时间相同，为当前时间
					memberLockManageDao.addMemberLockInfo(operatorInfo.getMemberNo(),operatorInfo.getOperatorId());
					tryTimes = Constants.TRY_TIMES_1;
				}
			}
		}
		else if(MemberLockStatus.MANUALLOCK == operatorInfo.getLockStatus())
		{
			//MANUALLOCK流程处理
			throw new MemberServiceException(MemberResponseCode.MEMBER_STATUS_HAS_MANUALLOCK,"member status is manualock!");//会员被管理员锁定，
		}
		else
		{
			//AUTOLOCK流程处理，是否在解锁时间内
			boolean  isOneCycle = DateUtil.isOneCycle(memberLockInfo.getCycleEndDate(),
					memberLockInfo.getCurrentDate(), loginFailUnlockTime);
			if(isOneCycle)
			{
				//没有到达解锁时间
				throw new MemberServiceException(MemberResponseCode.NOT_ARRIVE_UNLOCKTIME,"Automatically unlock the time has not arrived yet!");//没有超过解锁时间
			}
			else if(EncryptUtil.encryptPwd(pwd).equals(operatorInfo.getPwd()))
			{
				//到达解锁时间，且密码匹配：更新操作员最后成功登录时间，会员锁定状态NORAML，同时删除会员锁定表数据
				counts = operatorManagerDao.updateOperatorWhenLogin(operatorInfo , MemberLockStatus.NORMAL , true);//第三个参数为true：更新最后成功登入时间
				if(counts != 1)
				{
					throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
				}
				//密码匹配,清除会员表数据
				counts = memberLockManageDao.deleteMemberLockInfo(memberLockInfo.getMemberNo(),memberLockInfo.getOperatorID());
				if(counts != 1)
				{
					throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
				}
			}
			else
			{
				//到达解锁时间，且密码不匹配：更新操作员表会员锁定状态为NORAML，更新锁定表第一次登录失败时间，最后一次失败时间，失败次数为1
				counts = operatorManagerDao.updateOperatorWhenLogin(operatorInfo , MemberLockStatus.NORMAL , false);//第三个参数为false：更新最后成功登入时间
				if(counts != 1)
				{
					throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
				}
				counts = memberLockManageDao.updateMemberLockInfo(memberLockInfo.getMemberNo(),memberLockInfo.getOperatorID(),1 , true);//标示重置开始和结束时间
				if(counts != 1)
				{
					throw new MemberServiceException(MemberResponseCode.CAN_NOT_REPEAT_REQUEST,"can not repeat request");
				}
				tryTimes = Constants.TRY_TIMES_1;
			}
		}
		Map<String,Integer> retMap = new HashMap<String,Integer>();
		retMap.put("tryTimes", tryTimes);
		return retMap;
	}
	
	/**
	 * 
	 *
	 * 方法说明：获取合作方的会员ID的校验
	 * 
	 * @param sfMemberNo 对合作方会员号的校验
	 * @throws MemberServiceException 
	 */
	private void checkSystemParam(BaseParam... baseParams) throws MemberServiceException 
	{
		for(BaseParam baseParam : baseParams)
		{
			if(null == baseParam  || "".equals(baseParam.getParamValue()) 
					|| !CommonCheckUtil.isNumber(baseParam.getParamValue()))
			{
				throw new MemberServiceException(MemberResponseCode.ERROR_SYSTEM_PARAM,"Please check the system configuration information");
			}
		}
	}

	@Override
	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	public <T extends Member> void queryOperatorIsExist(T member)
			throws MemberServiceException
	{
		int  result = 0;
		try
		{
			result = operatorManagerDao.queryOperatorIsExist(null, member.getMobile(), 
					member.getEmail(), member.getLoginName(),member.getCertType(),member.getCertNo(),member.getMemberType());
		}
		catch(Exception e)
		{
			if(SQLException.class.isInstance(e.getCause()))
			{
				throw new MemberServiceException(MemberResponseCode.MEMBER_DB_EXCEPTION,"" + ((SQLException)(e.getCause())).getErrorCode(),e);
			}
			throw new MemberServiceException(MemberResponseCode.MEMBER_DB_EXCEPTION,"query data occur exception",e);
		}
		if(result != 0)
		{
			throw new MemberServiceException(MemberResponseCode.OPERATOR_HAS_REGISTER,"operator has exists : mobile: " + member.getMobile()+
				" ,email: "	+ member.getEmail()+ " ,loginName: " + member.getLoginName() + 
				" ,certType: " + member.getCertType() + " ,certNO: " + member.getCertNo());
		}
	}

	@Override
	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	public void queryEPMemberIsExist(EnterpriseMember epMemberExt)
			throws MemberServiceException
	{
		int  result = 0;
		try
		{
			 result  = enterpriseManageDao.queryEPMemberIsExist(epMemberExt);
		}
		catch(Exception  e)
		{
			if(SQLException.class.isInstance(e.getCause()))
			{
				throw new MemberServiceException(MemberResponseCode.MEMBER_DB_EXCEPTION,"" + ((SQLException)(e.getCause())).getErrorCode(),e);
			}
			throw new MemberServiceException(MemberResponseCode.MEMBER_DB_EXCEPTION,"query data occur exception",e);
		}
		if(result != 0)
		{
			throw new MemberServiceException(MemberResponseCode.MEMBER_HAS_REGISTER,"EP member has register , epMemberExt:" + epMemberExt.toString() );
		}
	}
}
